package org.flexthinker.binding.bean
{
    import org.flexthinker.binding.bean.support.PropertyResolutionError;
    import org.flexthinker.binding.value.PropertyChangeListener;
    import org.flexthinker.binding.value.support.MockBean;

    import org.flexthinker.binding.value.support.PropertyChangeListenerCounter;
    import org.hamcrest.assertThat;
    import org.hamcrest.core.throws;
    import org.hamcrest.object.equalTo;
    import org.hamcrest.object.instanceOf;

    /**
     * @author Dragos Dascalita Haut
     */
    public class BeanPropertyTest
    {
        private var mockBean:MockBean;
        private var beanProp:BeanProperty;

        public function BeanPropertyTest()
        {
        }

        [Before]
        public function setUp():void
        {
            mockBean = new MockBean();
            mockBean.simpleString = "myString";

            var bean:MockBean = new MockBean();
            bean.simpleString = "substring";
            mockBean.objectHolder = bean;
        }

        [Test]
        public function testReadingSimplePaths():void
        {
            beanProp = BeanProperty.create( "simpleString" );
            assertThat("BeanProperty shouldn't have any value without a source", beanProp.getValue(), equalTo(null));
            beanProp.setSource(mockBean);
            assertThat("BeanProperty.getValue() is wrong", beanProp.getValue(), equalTo(mockBean.simpleString));

            mockBean.simpleString = "someNewString";
            assertThat("BeanProperty.getValue() is wrong", beanProp.getValue(), equalTo(mockBean.simpleString));
        }

        [Test]
        public function testReadingComplexPaths():void
        {
            beanProp = BeanProperty.create( "objectHolder.simpleString" );
            assertThat("BeanProperty shouldn't have any value without a source", beanProp.getValue(), equalTo(null));
            beanProp.setSource(mockBean);
            assertThat("BeanProperty.getValue() is wrong", beanProp.getValue(), equalTo( MockBean(mockBean.objectHolder).simpleString));

            mockBean.objectHolder.simpleString = "someNewString";
            assertThat("BeanProperty.getValue() is wrong", beanProp.getValue(), equalTo( MockBean(mockBean.objectHolder).simpleString));
        }

        [Test]
        public function testWritingOnSimplePaths():void
        {
            var pcl:PropertyChangeListenerCounter  = new PropertyChangeListenerCounter();
            mockBean.bindableProperty = "I'm bindable";
            beanProp = BeanProperty.create( "bindableProperty" );
            beanProp.setSource(mockBean);
            beanProp.addValueChangeListener( pcl );
            beanProp.setValue("newStringValue");
            assertThat("BeanProperty.setValue() is wrong", mockBean.bindableProperty, equalTo("newStringValue"));
            assertThat("PropertyChangeListener should have been called", pcl.counter, equalTo(1) );

            mockBean.bindableProperty = "secondNewStringValue";
            assertThat("BeanProperty.setValue() is wrong", mockBean.bindableProperty, equalTo("secondNewStringValue"));
            assertThat("PropertyChangeListener should have been called", pcl.counter, equalTo(2) );
        }

        [Test]
        public function testBeanWritingWithComplexPath():void
        {
            var pcl:PropertyChangeListenerCounter  = new PropertyChangeListenerCounter();
            beanProp = BeanProperty.create( "objectHolder.bindableProperty" );
            beanProp.setSource(mockBean);
            beanProp.addValueChangeListener( pcl );
            beanProp.setValue("newStringValue");
            assertThat("BeanProperty.setValue() is wrong", mockBean.objectHolder.bindableProperty, equalTo("newStringValue"));
            assertThat("PropertyChangeListener should have been called", pcl.counter, equalTo(1) );

            mockBean.objectHolder.bindableProperty = "secondNewStringValue";
            assertThat("BeanProperty.setValue() is wrong", mockBean.objectHolder.bindableProperty, equalTo("secondNewStringValue"));
            assertThat("PropertyChangeListener should have been called", pcl.counter, equalTo(2) );
        }


        //negative tests
        [Test]
        public function testBeanReadingOnSetterOnly():void
        {
           beanProp = BeanProperty.create( "objectHolder.setOnlyProp" );
           assertThat( function():void
           {
              beanProp.setSource(mockBean);
           }, throws(instanceOf(PropertyResolutionError)));
        }

        [Test]
        public function testBeanWritingOnGetterOnly():void
        {
            beanProp = BeanProperty.create( "objectHolder.getOnlyProp" );
            beanProp.setSource(mockBean);
            assertThat("BeanProperty.getvalue() is wrong on read-only props", beanProp.getValue(), equalTo(mockBean.objectHolder.getOnlyProp));
            assertThat( function():void
            {
                beanProp.setValue("invalidOperation");
            }, throws(instanceOf(PropertyResolutionError)));
        }

    }
}